Ext.form.MultiComboBox = Ext.extend(Ext.form.TriggerField, {   
    defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},   
    listClass: '',   
    selectedClass: 'x-combo-selected',   
    triggerClass : 'x-form-arrow-trigger',   
    shadow:'sides',   
    listAlign: 'tl-bl?',   
    maxHeight: 300,   
    triggerAction: 'query',   
    minChars : 4,   
    typeAhead: false,   
    queryDelay: 500,   
    pageSize: 0,   
    selectOnFocus:false,   
    queryParam: 'query',   
    loadingText: 'Loading...',   
    resizable: false,   
    handleHeight : 8,   
    editable: true,   
    allQuery: '',   
    mode: 'remote',   
    minListWidth : 70,   
    forceSelection:false,   
    typeAheadDelay : 250,   
    displaySeparator:';',   
    valueSeparator:',',   
    lazyInit : true,   
  
    initComponent : function(){   
        Ext.form.ComboBox.superclass.initComponent.call(this);   
        this.addEvents(   
            'expand',   
            'collapse',   
            'beforeselect',   
            'select',   
            'beforequery'  
        );   
        if(this.transform){   
            this.allowDomMove = false;   
            var s = Ext.getDom(this.transform);   
            if(!this.hiddenName){   
                this.hiddenName = s.name;   
            }   
            if(!this.store){   
                this.mode = 'local';   
                var d = [], opts = s.options;   
                for(var i = 0, len = opts.length;i < len; i++){   
                    var o = opts[i];   
                    var value = (Ext.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;   
                    if(o.selected) {   
                        this.value = value;   
                    }   
                    d.push([value, o.text]);   
                }   
                this.store = new Ext.data.SimpleStore({   
                    'id': 0,   
                    fields: ['value', 'text'],   
                    data : d   
                });   
                this.valueField = 'value';   
                this.displayField = 'text';   
            }   
            s.name = Ext.id(); // wipe out the name in case somewhere else they have a reference   
            if(!this.lazyRender){   
                this.target = true;   
                this.el = Ext.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);   
                Ext.removeNode(s); // remove it   
                this.render(this.el.parentNode);   
            }else{   
                Ext.removeNode(s); // remove it   
            }   
  
        }   
        this.selectedIndex = -1;   
        if(this.mode == 'local'){   
            if(this.initialConfig.queryDelay === undefined){   
                this.queryDelay = 10;   
            }   
            if(this.initialConfig.minChars === undefined){   
                this.minChars = 0;   
            }   
        }   
    },   
  
    // private   
    onRender : function(ct, position){   
        Ext.form.ComboBox.superclass.onRender.call(this, ct, position);   
        var disValue="";   
        if(this.hiddenName){   
            this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},   
                    'before', true);   
          var hvalue=this.hiddenValue !== undefined ? this.hiddenValue :   
                this.value !== undefined ? this.value : '';   
          var hvalueArray=hvalue.split(this.valueSeparator);   
             
          for(var i=0;i<this.store.data.length;i++){   
                 var r = this.store.getAt(i);      
                 var newValue = r.data[this.displayField];   
                  var v=r.data[this.valueField];   
                  for(var j=0;j<hvalueArray.length;j++){   
                    if(hvalueArray[j]==v){   
                        disValue+=newValue+this.displaySeparator;   
                    }   
                  }   
                    
          }        
            this.hiddenField.value =this.hiddenValue !== undefined ? this.hiddenValue :   
                this.value !== undefined ? this.value : '';   
            this.el.dom.removeAttribute('name');   
        }   
        if(Ext.isGecko){   
            this.el.dom.setAttribute('autocomplete', 'off');   
        }   
  
        if(!this.lazyInit){   
            this.initList();   
        }else{   
            this.on('focus', this.initList, this, {single: true});   
        }   
  
        if(!this.editable){   
            this.editable = true;   
            this.setEditable(false);   
        }   
        this.setValue(disValue);   
    },   
  
    initList : function(){   
        if(!this.list){   
            var cls = 'x-combo-list';   
  
            this.list = new Ext.Layer({   
                shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false  
            });   
  
            var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);   
            this.list.setWidth(lw);   
            this.list.swallowEvent('mousewheel');   
            this.assetHeight = 0;   
  
            if(this.title){   
                this.header = this.list.createChild({cls:cls+'-hd', html: this.title});   
                this.assetHeight += this.header.getHeight();   
            }   
  
            this.innerList = this.list.createChild({cls:cls+'-inner'});   
            this.innerList.on('mouseover', this.onViewOver, this);   
            this.innerList.on('mousemove', this.onViewMove, this);   
            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
            this.innerList.setHeight(this.layerHeight || this.minLayerHeight);       
  
            if(this.pageSize){   
                this.footer = this.list.createChild({cls:cls+'-ft'});   
                this.pageTb = new Ext.PagingToolbar({   
                    store:this.store,   
                    pageSize: this.pageSize,   
                    renderTo:this.footer   
                });   
                this.assetHeight += this.footer.getHeight();   
            }   
  
            if(!this.tpl){   
                //alert(cls);   
                //x-combo-list-item   
                this.tpl = '<tpl for="."><div class="'+cls+'-item"><span class="unchecked" id="checkBox_{' + this.displayField + '}"+ width="20">&nbsp;&nbsp;&nbsp;&nbsp;</span>{' + this.displayField + '}</div></tpl>';   
            }   
            this.view = new Ext.DataView({   
                applyTo: this.innerList,   
                tpl: this.tpl,   
                singleSelect: true,   
                selectedClass: this.selectedClass,   
                itemSelector: this.itemSelector || '.' + cls + '-item'  
            });   
  
            this.view.on('click', this.onViewClick, this);   
  
            this.bindStore(this.store, true);   
  
            if(this.resizable){   
                this.resizer = new Ext.Resizable(this.list,  {   
                   pinned:true, handles:'se'  
                });   
                this.resizer.on('resize', function(r, w, h){   
                    this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;   
                    this.listWidth = w;   
                    this.innerList.setWidth(w - this.list.getFrameWidth('lr'));   
                    this.restrictHeight();   
                }, this);   
                this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');   
            }   
        }   
    },   
  
    bindStore : function(store, initial){   
        if(this.store && !initial){   
            this.store.un('beforeload', this.onBeforeLoad, this);   
            this.store.un('load', this.onLoad, this);   
            this.store.un('loadexception', this.collapse, this);   
            if(!store){   
                this.store = null;   
                if(this.view){   
                    this.view.setStore(null);   
                }   
            }   
        }   
        if(store){   
            this.store = Ext.StoreMgr.lookup(store);   
  
            this.store.on('beforeload', this.onBeforeLoad, this);   
            this.store.on('load', this.onLoad, this);   
            this.store.on('loadexception', this.collapse, this);   
  
            if(this.view){   
                this.view.setStore(store);   
            }   
        }   
    },   
  
    // private   
    initEvents : function(){   
        Ext.form.ComboBox.superclass.initEvents.call(this);   
  
        this.keyNav = new Ext.KeyNav(this.el, {   
            "up" : function(e){   
                this.inKeyMode = true;   
                this.selectPrev();   
            },   
  
            "down" : function(e){   
                if(!this.isExpanded()){   
                    this.onTriggerClick();   
                }else{   
                    this.inKeyMode = true;   
                    this.selectNext();   
                }   
            },   
  
            "enter" : function(e){   
                this.onViewClick();   
                //return true;   
            },   
  
            "esc" : function(e){   
                this.collapse();   
            },   
  
            "tab" : function(e){   
                this.onViewClick(false);   
                return true;   
            },   
  
            scope : this,   
  
            doRelay : function(foo, bar, hname){   
                if(hname == 'down' || this.scope.isExpanded()){   
                   return Ext.KeyNav.prototype.doRelay.apply(this, arguments);   
                }   
                return true;   
            },   
  
            forceKeyDown : true  
        });   
        this.queryDelay = Math.max(this.queryDelay || 10,   
                this.mode == 'local' ? 10 : 250);   
        this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);   
        if(this.typeAhead){   
            this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);   
        }   
        if(this.editable !== false){   
            this.el.on("keyup", this.onKeyUp, this);   
        }   
        if(this.forceSelection){   
            this.on('blur', this.doForce, this);   
        }   
    },   
  
    onDestroy : function(){   
        if(this.view){   
            this.view.el.removeAllListeners();   
            this.view.el.remove();   
            this.view.purgeListeners();   
        }   
        if(this.list){   
            this.list.destroy();   
        }   
        this.bindStore(null);   
        Ext.form.ComboBox.superclass.onDestroy.call(this);   
    },   
  
    // private   
    fireKey : function(e){   
        if(e.isNavKeyPress() && !this.list.isVisible()){   
            this.fireEvent("specialkey", this, e);   
        }   
    },   
  
    // private   
    onResize: function(w, h){   
        Ext.form.ComboBox.superclass.onResize.apply(this, arguments);   
        if(this.list && this.listWidth === undefined){   
            var lw = Math.max(w, this.minListWidth);   
            this.list.setWidth(lw);   
            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));   
        }   
    },   
  
    // private   
    onDisable: function(){   
        Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);   
        if(this.hiddenField){   
            this.hiddenField.disabled = this.disabled;   
        }   
    },   
    setEditable : function(value){   
        if(value == this.editable){   
            return;   
        }   
        this.editable = value;   
        if(!value){   
            this.el.dom.setAttribute('readOnly', true);   
            this.el.on('mousedown', this.onTriggerClick,  this);   
            this.el.addClass('x-combo-noedit');   
        }else{   
            this.el.dom.setAttribute('readOnly', false);   
            this.el.un('mousedown', this.onTriggerClick,  this);   
            this.el.removeClass('x-combo-noedit');   
        }   
    },   
  
    // private   
    onBeforeLoad : function(){   
        if(!this.hasFocus){   
            return;   
        }   
        this.innerList.update(this.loadingText ?   
               '<div class="loading-indicator">'+this.loadingText+'</div>' : '');   
        this.restrictHeight();   
        this.selectedIndex = -1;   
    },   
  
    // private   
    onLoad : function(){   
        if(!this.hasFocus){   
            return;   
        }   
        if(this.store.getCount() > 0){   
            this.expand();   
            this.restrictHeight();   
            if(this.lastQuery == this.allQuery){   
                if(this.editable){   
                    this.el.dom.select();   
                }   
                if(!this.selectByValue(this.value, true)){   
                    this.select(0, true);   
                }   
            }else{   
                this.selectNext();   
                if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){   
                    this.taTask.delay(this.typeAheadDelay);   
                }   
            }   
        }else{   
            this.onEmptyResults();   
        }   
    },   
  
    // private   
    onTypeAhead : function(){   
        if(this.store.getCount() > 0){   
            var r = this.store.getAt(0);   
            var newValue = r.data[this.displayField];   
            var len = newValue.length;   
            var selStart = this.getRawValue().length;   
            if(selStart != len){   
                this.setRawValue(newValue);   
                this.selectText(selStart, newValue.length);   
            }   
        }   
    },   
    // private   
    onSelect : function(record, index){   
        if(this.fireEvent('beforeselect', this, record, index) !== false){   
            var r = this.store.getAt(index);   
            var newValue = r.data[this.displayField];   
            var check=document.getElementById("checkBox_"+newValue);   
            if(check.className=="checked"){   
                check.className="unchecked"  
            }else{   
                check.className="checked"  
            }   
            var value="";    
            var hiddenValue="";   
            for(var i=0;i<this.store.data.length;i++){   
                 var r = this.store.getAt(i);      
                 newValue = r.data[this.displayField];   
                 check=document.getElementById("checkBox_"+newValue);   
                 if(check.className=="checked"){   
                    value+= r.data[this.displayField]+this.displaySeparator;   
                    hiddenValue+= r.data[this.valueField]+this.valueSeparator;   
                 }   
            }   
            if(value.length>1){   
                value=value.substring(0,value.length-this.displaySeparator.length);   
            }   
            if(hiddenValue.length>1){   
                hiddenValue=hiddenValue.substring(0,value.length-this.valueSeparator.length);   
            }   
            this.setValue(value);   
            this.hiddenField.value=hiddenValue;   
            this.fireEvent('select', this, record, index);   
        }   
    },   
    getValue : function(){   
        if(this.valueField){   
            return typeof this.value != 'undefined' ? this.value : '';   
        }else{   
            return Ext.form.ComboBox.superclass.getValue.call(this);   
        }   
    },   
  
    /**  
     * Clears any text/value currently set in the field  
     */  
    clearValue : function(){   
        if(this.hiddenField){   
            this.hiddenField.value = '';   
        }   
        this.setRawValue('');   
        this.lastSelectionText = '';   
        this.applyEmptyText();   
    },   
    setValue : function(v){   
        var text = v;   
        if(this.valueField){   
            var r = this.findRecord(this.valueField, v);   
            if(r){   
                text = r.data[this.displayField];   
            }else if(this.valueNotFoundText !== undefined){   
                text = this.valueNotFoundText;   
            }   
        }   
        this.lastSelectionText = text;   
        Ext.form.ComboBox.superclass.setValue.call(this, text);   
        this.value = v;   
    },   
  
    // private   
    findRecord : function(prop, value){   
        var record;   
        if(this.store.getCount() > 0){   
            this.store.each(function(r){   
                if(r.data[prop] == value){   
                    record = r;   
                    return false;   
                }   
            });   
        }   
        return record;   
    },   
  
    // private   
    onViewMove : function(e, t){   
        this.inKeyMode = false;   
    },   
  
    // private   
    onViewOver : function(e, t){   
        if(this.inKeyMode){ // prevent key nav and mouse over conflicts   
            return;   
        }   
        var item = this.view.findItemFromChild(t);   
        if(item){   
            var index = this.view.indexOf(item);   
            this.select(index, false);   
        }   
    },   
  
    // private   
    onViewClick : function(doFocus){   
        var index = this.view.getSelectedIndexes()[0];   
        var r = this.store.getAt(index);   
        if(r){   
            this.onSelect(r, index);   
        }   
        if(doFocus !== false){   
            this.el.focus();   
        }   
    },   
  
    // private   
    restrictHeight : function(){   
        this.innerList.dom.style.height = '';   
        var inner = this.innerList.dom;   
        var fw = this.list.getFrameWidth('tb');   
        var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);   
        this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);   
        this.list.beginUpdate();   
        this.list.setHeight(this.innerList.getHeight()+fw+(this.resizable?this.handleHeight:0)+this.assetHeight);   
        this.list.alignTo(this.el, this.listAlign);   
        this.list.endUpdate();   
    },   
  
    // private   
    onEmptyResults : function(){   
        this.collapse();   
    },   
  
    /**  
     * Returns true if the dropdown list is expanded, else false.  
     */  
    isExpanded : function(){   
        return this.list && this.list.isVisible();   
    },   
    selectByValue : function(v, scrollIntoView){   
        if(v !== undefined && v !== null){   
            var r = this.findRecord(this.valueField || this.displayField, v);   
            if(r){   
                this.select(this.store.indexOf(r), scrollIntoView);   
                return true;   
            }   
        }   
        return false;   
    },   
    select : function(index, scrollIntoView){   
           
        this.selectedIndex = index;   
        this.view.select(index);   
        if(scrollIntoView !== false){   
            var el = this.view.getNode(index);   
            if(el){   
                this.innerList.scrollChildIntoView(el, false);   
            }   
        }   
    },   
  
    // private   
    selectNext : function(){   
        var ct = this.store.getCount();   
        if(ct > 0){   
            if(this.selectedIndex == -1){   
                this.select(0);   
            }else if(this.selectedIndex < ct-1){   
                this.select(this.selectedIndex+1);   
            }   
        }   
    },   
  
    // private   
    selectPrev : function(){   
        var ct = this.store.getCount();   
        if(ct > 0){   
            if(this.selectedIndex == -1){   
                this.select(0);   
            }else if(this.selectedIndex != 0){   
                this.select(this.selectedIndex-1);   
            }   
        }   
    },   
  
    // private   
    onKeyUp : function(e){   
        if(this.editable !== false && !e.isSpecialKey()){   
            this.lastKey = e.getKey();   
            this.dqTask.delay(this.queryDelay);   
        }   
    },   
  
    // private   
    validateBlur : function(){   
        return !this.list || !this.list.isVisible();      
    },   
  
    // private   
    initQuery : function(){   
        this.doQuery(this.getRawValue());   
    },   
  
    // private   
    doForce : function(){   
        if(this.el.dom.value.length > 0){   
            this.el.dom.value =   
                this.lastSelectionText === undefined ? '' : this.lastSelectionText;   
            this.applyEmptyText();   
        }   
    },   
    doQuery : function(q, forceAll){   
        if(q === undefined || q === null){   
            q = '';   
        }   
        var qe = {   
            query: q,   
            forceAll: forceAll,   
            combo: this,   
            cancel:false  
        };   
        if(this.fireEvent('beforequery', qe)===false || qe.cancel){   
            return false;   
        }   
        q = qe.query;   
        forceAll = qe.forceAll;   
        if(forceAll === true || (q.length >= this.minChars)){   
            if(this.lastQuery !== q){   
                this.lastQuery = q;   
                if(this.mode == 'local'){   
                    this.selectedIndex = -1;   
                    if(forceAll){   
                        this.store.clearFilter();   
                    }else{   
                        this.store.filter(this.displayField, q);   
                    }   
                    this.onLoad();   
                }else{   
                    this.store.baseParams[this.queryParam] = q;   
                    this.store.load({   
                        params: this.getParams(q)   
                    });   
                    this.expand();   
                }   
            }else{   
                this.selectedIndex = -1;   
                this.onLoad();      
            }   
        }   
    },   
  
    // private   
    getParams : function(q){   
        var p = {};   
        //p[this.queryParam] = q;   
        if(this.pageSize){   
            p.start = 0;   
            p.limit = this.pageSize;   
        }   
        return p;   
    },   
    /**  
     * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.  
     */  
    collapse : function(){   
        if(!this.isExpanded()){   
            return;   
        }   
        this.list.hide();   
        Ext.getDoc().un('mousewheel', this.collapseIf, this);   
        Ext.getDoc().un('mousedown', this.collapseIf, this);   
        this.fireEvent('collapse', this);   
    },   
    // private   
    collapseIf : function(e){   
        if(!e.within(this.wrap) && !e.within(this.list)){   
            this.collapse();   
        }   
    },   
       
    /**  
     * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.  
     */  
    expand : function(){   
        if(this.isExpanded() || !this.hasFocus){   
            return;   
        }   
        this.list.alignTo(this.wrap, this.listAlign);   
        var hvalueArray=this.hiddenField.value.split(this.valueSeparator);   
        for(var i=0;i<this.store.data.length;i++){   
             var r = this.store.getAt(i);      
             var newValue = r.data[this.displayField];   
              var v=r.data[this.valueField];   
              for(var j=0;j<hvalueArray.length;j++){   
                if(hvalueArray[j]==v){   
                    document.getElementById("checkBox_"+newValue).className="checked";   
                }   
              }   
                
        }    
        this.list.show();   
        Ext.getDoc().on('mousewheel', this.collapseIf, this);   
        Ext.getDoc().on('mousedown', this.collapseIf, this);   
        this.fireEvent('expand', this);   
    },   
  
    // private   
    // Implements the default empty TriggerField.onTriggerClick function   
    onTriggerClick : function(){   
        if(this.disabled){   
            return;   
        }   
        if(this.isExpanded()){   
            this.collapse();   
            this.el.focus();   
        }else {   
            this.onFocus({});   
            if(this.triggerAction == 'all') {   
                this.doQuery(this.allQuery, true);   
            } else {   
                this.doQuery(this.getRawValue());   
            }   
            this.el.focus();   
        }   
    }   
});   
Ext.reg('multicombo', Ext.form.MultiComboBox);  
